{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "whjsJasuhstV"
   },
   "source": [
    "<a href=\"https://colab.research.google.com/github/jeffheaton/app_generative_ai/blob/main/t81_559_class_04_5_memory_persist.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "euOZxlIMhstX"
   },
   "source": [
    "# T81-559: Applications of Generative Artificial Intelligence\n",
    "**Module 4: LangChain: Chat and Memory**\n",
    "* Instructor: [Jeff Heaton](https://sites.wustl.edu/jeffheaton/), McKelvey School of Engineering, [Washington University in St. Louis](https://engineering.wustl.edu/Programs/Pages/default.aspx)\n",
    "* For more information visit the [class website](https://sites.wustl.edu/jeffheaton/t81-558/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d4Yov72PhstY"
   },
   "source": [
    "# Module 4 Material\n",
    "\n",
    "* Part 4.1: LangChain Conversations [[Video]](https://www.youtube.com/watch?v=Effbhxq07Ag) [[Notebook]](t81_559_class_04_1_langchain_chat.ipynb)\n",
    "* Part 4.2: Conversation Buffer Window Memory [[Video]](https://www.youtube.com/watch?v=14RgiFVGfAA) [[Notebook]](t81_559_class_04_2_memory_buffer.ipynb)\n",
    "* Part 4.3: Conversation Token Buffer Memory [[Video]](https://www.youtube.com/watch?v=QTe5g2c3bSM) [[Notebook]](t81_559_class_04_3_memory_token.ipynb)\n",
    "* Part 4.4: Conversation Summary Memory [[Video]](https://www.youtube.com/watch?v=asZQ8Ktqmt8) [[Notebook]](t81_559_class_04_4_memory_summary.ipynb)\n",
    "* **Part 4.5: Persisting Langchain Memory** [[Video]](https://www.youtube.com/watch?v=sjCyqqOQcPA) [[Notebook]](t81_559_class_04_5_memory_persist.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AcAUP0c3hstY"
   },
   "source": [
    "# Google CoLab Instructions\n",
    "\n",
    "The following code ensures that Google CoLab is running and maps Google Drive if needed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "xsI496h5hstZ",
    "outputId": "54665e47-e883-433d-ff27-8165abcf168d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Note: using Google CoLab\n",
      "Requirement already satisfied: langchain in /usr/local/lib/python3.10/dist-packages (0.1.17)\n",
      "Requirement already satisfied: langchain_openai in /usr/local/lib/python3.10/dist-packages (0.1.5)\n",
      "Requirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (6.0.1)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.0.29)\n",
      "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (3.9.5)\n",
      "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (4.0.3)\n",
      "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.6.5)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.33)\n",
      "Requirement already satisfied: langchain-community<0.1,>=0.0.36 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.0.36)\n",
      "Requirement already satisfied: langchain-core<0.2.0,>=0.1.48 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.1.48)\n",
      "Requirement already satisfied: langchain-text-splitters<0.1,>=0.0.1 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.0.1)\n",
      "Requirement already satisfied: langsmith<0.2.0,>=0.1.17 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.1.52)\n",
      "Requirement already satisfied: numpy<2,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.25.2)\n",
      "Requirement already satisfied: pydantic<3,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.7.1)\n",
      "Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.31.0)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (8.2.3)\n",
      "Requirement already satisfied: openai<2.0.0,>=1.10.0 in /usr/local/lib/python3.10/dist-packages (from langchain_openai) (1.25.0)\n",
      "Requirement already satisfied: tiktoken<1,>=0.5.2 in /usr/local/lib/python3.10/dist-packages (from langchain_openai) (0.6.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.1)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (23.2.0)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.4.1)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.0.5)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.9.4)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in /usr/local/lib/python3.10/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (3.21.2)\n",
      "Requirement already satisfied: typing-inspect<1,>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (0.9.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.10/dist-packages (from jsonpatch<2.0,>=1.33->langchain) (2.4)\n",
      "Requirement already satisfied: packaging<24.0,>=23.2 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.48->langchain) (23.2)\n",
      "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in /usr/local/lib/python3.10/dist-packages (from langsmith<0.2.0,>=0.1.17->langchain) (3.10.2)\n",
      "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (3.7.1)\n",
      "Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (1.7.0)\n",
      "Requirement already satisfied: httpx<1,>=0.23.0 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (0.27.0)\n",
      "Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (1.3.1)\n",
      "Requirement already satisfied: tqdm>4 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (4.66.2)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.7 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (4.11.0)\n",
      "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (0.6.0)\n",
      "Requirement already satisfied: pydantic-core==2.18.2 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (2.18.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.7)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2.0.7)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2024.2.2)\n",
      "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy<3,>=1.4->langchain) (3.0.3)\n",
      "Requirement already satisfied: regex>=2022.1.18 in /usr/local/lib/python3.10/dist-packages (from tiktoken<1,>=0.5.2->langchain_openai) (2023.12.25)\n",
      "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->openai<2.0.0,>=1.10.0->langchain_openai) (1.2.1)\n",
      "Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.10/dist-packages (from httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain_openai) (1.0.5)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in /usr/local/lib/python3.10/dist-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain_openai) (0.14.0)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in /usr/local/lib/python3.10/dist-packages (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain) (1.0.0)\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "try:\n",
    "    from google.colab import drive, userdata\n",
    "    COLAB = True\n",
    "    print(\"Note: using Google CoLab\")\n",
    "except:\n",
    "    print(\"Note: not using Google CoLab\")\n",
    "    COLAB = False\n",
    "\n",
    "# OpenAI Secrets\n",
    "if COLAB:\n",
    "    os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY')\n",
    "\n",
    "# Install needed libraries in CoLab\n",
    "if COLAB:\n",
    "    !pip install langchain langchain_openai"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pC9A-LaYhsta"
   },
   "source": [
    "# 4.5: Persisting Langchain Memory\n",
    "\n",
    "In this section, we delve into the creation of an innovative utility class designed for managing chat interactions—aptly named ChatBot. This class stands as a cornerstone for applications that require robust handling of chat history, including features to load and save these interactions, as well as capabilities to undo or regenerate outputs. The architecture of ChatBot integrates advanced language models with structured templates to facilitate interactive conversations, ensuring a seamless and dynamic user experience.\n",
    "\n",
    "The core functionality of ChatBot revolves around its sophisticated integration of components from the langchain ecosystem. It utilizes a large language model for generating chat responses and another for summarizing conversations, complemented by a template that structures each interaction. Key features include maintaining an editable conversation history, implementing undo and regenerate operations for greater control over chat flows, and mechanisms to persist conversation states, enhancing the utility and flexibility of the chat interface. As we explore ChatBot, we will uncover how each component contributes to its overall capability to manage complex conversational contexts effectively.\n",
    "\n",
    "The code for this class follows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "TMF-rtxgRAea"
   },
   "outputs": [],
   "source": [
    "from langchain.chains import ConversationChain\n",
    "from langchain.memory import ConversationSummaryMemory\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.prompts.chat import PromptTemplate\n",
    "from IPython.display import display_markdown\n",
    "import pickle\n",
    "\n",
    "DEFAULT_TEMPLATE = \"\"\"You are a helpful assistant. Format answers with markdown.\n",
    "\n",
    "Current conversation:\n",
    "{history}\n",
    "Human: {input}\n",
    "AI:\"\"\"\n",
    "\n",
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "class ChatBot:\n",
    "    def __init__(self, llm_chat, llm_summary, template):\n",
    "        \"\"\"\n",
    "        Initializes the ChatBot with language models and a template for conversation.\n",
    "\n",
    "        :param llm_chat: A large language model for handling chat responses.\n",
    "        :param llm_summary: A large language model for summarizing conversations.\n",
    "        :param template: A string template defining the conversation structure.\n",
    "        \"\"\"\n",
    "        self.llm_chat = llm_chat\n",
    "        self.llm_summary = llm_summary\n",
    "        self.template = template\n",
    "        self.prompt_template = PromptTemplate(input_variables=[\"history\", \"input\"], template=self.template)\n",
    "\n",
    "        # Initialize memory and conversation chain\n",
    "        self.memory = ConversationSummaryMemory(llm=self.llm_summary)\n",
    "        self.conversation = ConversationChain(\n",
    "            prompt=self.prompt_template,\n",
    "            llm=self.llm_chat,\n",
    "            memory=self.memory,\n",
    "            verbose=False\n",
    "        )\n",
    "\n",
    "        self.history = []\n",
    "\n",
    "    def converse(self, prompt):\n",
    "        \"\"\"\n",
    "        Processes a conversation prompt and updates the internal history and memory.\n",
    "\n",
    "        :param prompt: The input prompt from the user.\n",
    "        :return: The generated response from the language model.\n",
    "        \"\"\"\n",
    "        self.history.append([self.memory.buffer, prompt])\n",
    "        output = self.conversation.invoke(prompt)\n",
    "        return output['response']\n",
    "\n",
    "    def chat(self, prompt):\n",
    "        \"\"\"\n",
    "        Handles the full cycle of receiving a prompt, processing it, and displaying the result.\n",
    "\n",
    "        :param prompt: The input prompt from the user.\n",
    "        \"\"\"\n",
    "        print(f\"Human: {prompt}\")\n",
    "        output = self.converse(prompt)\n",
    "        display_markdown(output, raw=True)\n",
    "\n",
    "    def print_memory(self):\n",
    "        \"\"\"\n",
    "        Displays the current state of the conversation memory.\n",
    "        \"\"\"\n",
    "        print(\"**Memory:\")\n",
    "        print(self.memory.buffer)\n",
    "\n",
    "    def clear_memory(self):\n",
    "        \"\"\"\n",
    "        Clears the conversation memory.\n",
    "        \"\"\"\n",
    "        self.memory.clear()\n",
    "\n",
    "    def undo(self):\n",
    "        \"\"\"\n",
    "        Reverts the conversation memory to the state before the last interaction.\n",
    "        \"\"\"\n",
    "        if len(self.history) > 0:\n",
    "            self.memory.buffer = self.history.pop()[0]\n",
    "        else:\n",
    "            print(\"Nothing to undo.\")\n",
    "\n",
    "    def regenerate(self):\n",
    "        \"\"\"\n",
    "        Re-executes the last undone interaction, effectively redoing an undo operation.\n",
    "        \"\"\"\n",
    "        if len(self.history) > 0:\n",
    "            self.memory.buffer, prompt = self.history.pop()\n",
    "            self.chat(prompt)\n",
    "        else:\n",
    "            print(\"Nothing to regenerate.\")\n",
    "\n",
    "    def save_history(self, file_path):\n",
    "        \"\"\"\n",
    "        Saves the conversation history to a file using pickle.\n",
    "\n",
    "        :param file_path: The file path where the history should be saved.\n",
    "        \"\"\"\n",
    "        with open(file_path, 'wb') as f:\n",
    "            pickle.dump(self.history, f)\n",
    "\n",
    "    def load_history(self, file_path):\n",
    "        \"\"\"\n",
    "        Loads the conversation history from a file using pickle.\n",
    "\n",
    "        :param file_path: The file path from which to load the history.\n",
    "        \"\"\"\n",
    "        with open(file_path, 'rb') as f:\n",
    "            self.history = pickle.load(f)\n",
    "            # Optionally reset the memory based on the last saved state\n",
    "            if self.history:\n",
    "                self.memory.buffer = self.history[-1][0]\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6zJA-AF8vBtW"
   },
   "source": [
    "## Testing the Chat Bot\n",
    "Before we see how this class was constructed, lets see how you can use it. The following shows a simple chat interaction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 206
    },
    "id": "tXJAk_dAtuFb",
    "outputId": "eaf8236d-6f3d-4ad9-bc0f-bef02873364a"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Hello, my name is Jeff.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Hello Jeff! How can I assist you today?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: I like coffee.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "That's great to hear, Jeff! How do you like your coffee prepared?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: What is my name.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Hello! How can I assist you today?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Do I like coffee?\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "It seems like you do like coffee! How do you like your coffee prepared?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "# Initialize the OpenAI LLM with your API key\n",
    "llm = ChatOpenAI(\n",
    "  model=MODEL,\n",
    "  temperature= 0.3,\n",
    "  n= 1)\n",
    "\n",
    "c = ChatBot(llm, llm, DEFAULT_TEMPLATE)\n",
    "\n",
    "c.chat(\"Hello, my name is Jeff.\")\n",
    "c.chat(\"I like coffee.\")\n",
    "c.chat(\"What is my name.\")\n",
    "c.chat(\"Do I like coffee?\")\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rEut99OTt_AG"
   },
   "source": [
    "## Load and Save Chat Memory\n",
    "\n",
    "The chat bot allows the complete chat history and memory to be saved and loaded from a file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 206
    },
    "id": "Z09iSHYvt8is",
    "outputId": "4ece6ca7-776f-49f7-ecea-0e7e535e04b7"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Hello, my name is Jeff.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Hello Jeff! How can I assist you today?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: I like coffee.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "That's great to hear, Jeff! How do you like your coffee?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: What is my name.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Your name is Jeff."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Do I like coffee?\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "It seems like you do! How do you like your coffee, Jeff?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "# Initialize the OpenAI LLM with your API key\n",
    "llm = ChatOpenAI(\n",
    "  model=MODEL,\n",
    "  temperature= 0.3,\n",
    "  n= 1)\n",
    "\n",
    "c = ChatBot(llm, llm, DEFAULT_TEMPLATE)\n",
    "c.chat(\"Hello, my name is Jeff.\")\n",
    "c.chat(\"I like coffee.\")\n",
    "c.chat(\"What is my name.\")\n",
    "c.chat(\"Do I like coffee?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7ScF3OysvTWk"
   },
   "source": [
    "We now save the chat memory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "pllixtJUuDP0"
   },
   "outputs": [],
   "source": [
    "c.save_history('history.pkl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wUvlZe3FvW-0"
   },
   "source": [
    "You can now reload the chat memory; the bot should remember the discussion."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 64
    },
    "id": "O3O2kcEzuFvF",
    "outputId": "eb72fde1-1619-4c13-d329-21781e5ed96a"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: What is my name?\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Your name is Jeff."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "c = ChatBot(llm, llm, DEFAULT_TEMPLATE)\n",
    "c.load_history('history.pkl')\n",
    "c.chat(\"What is my name?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ClPhLkGldhPt"
   },
   "source": [
    "## Undoing and Regenerating the Chat\n",
    "\n",
    "The chatbot allows us to undo parts of the conversation, and it forgets. We can also regenerate outputs to get a better response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 253
    },
    "id": "ydaqwgRiH4D6",
    "outputId": "11aaa405-6a00-4a82-e6d8-bcdf9adb6f45"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Hello, my name is Jeff.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Hello Jeff! How can I assist you today?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: I like coffee.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "That's great to hear, Jeff! How do you like your coffee?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: What is my name.\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "Your name is Jeff. How can I assist you today?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Do I like coffee?\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "I'm sorry, but as an AI assistant, I do not have access to personal information about your likes and dislikes."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: Do I like coffee?\n"
     ]
    },
    {
     "data": {
      "text/markdown": [
       "It seems like you forgot to provide information on whether you like coffee or not. Would you like me to assist you in determining if you like coffee?"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "# Initialize the OpenAI LLM with your API key\n",
    "llm = ChatOpenAI(\n",
    "  model=MODEL,\n",
    "  temperature= 0.3,\n",
    "  n= 1)\n",
    "\n",
    "c = ChatBot(llm, llm, DEFAULT_TEMPLATE)\n",
    "\n",
    "c.chat(\"Hello, my name is Jeff.\")\n",
    "c.chat(\"I like coffee.\")\n",
    "c.undo()\n",
    "c.chat(\"What is my name.\")\n",
    "c.chat(\"Do I like coffee?\")\n",
    "c.regenerate()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "KrNDYZ5rw1e_"
   },
   "source": [
    "## Implementing the Chatbot\n",
    "\n",
    "In this section, we delve into the architecture of a sophisticated chatbot built using the LangChain and OpenAI libraries, encapsulated within the ChatBot class. The ChatBot class leverages two language models and a structured conversation template to engage users in a dynamic conversational flow.\n",
    "\n",
    "The class initiates by defining its basic components: llm_chat and llm_summary are large language models used for chat responses and conversation summarization, respectively. The template parameter defines the conversation's structure, guiding how interactions are formatted and presented. This template incorporates markdown formatting and placeholders for the conversation history and the latest user input, facilitating a clear and structured dialogue presentation.\n",
    "\n",
    "Upon instantiation, the ChatBot initializes various components. It constructs a PromptTemplate, which prepares the structure for input variables and the conversation template. The ConversationSummaryMemory, initialized with the llm_summary, acts as a dynamic storage for conversation excerpts, aiding in recalling context or summarizing past dialogues. This memory component is crucial for maintaining conversation continuity, especially in sessions that might span multiple interactions.\n",
    "\n",
    "The ConversationChain is another pivotal element, combining the prompt template with the llm_chat model to process and respond to user inputs. The chain's verbose mode is set to False to streamline output without extraneous system messages.\n",
    "\n",
    "Interaction with the ChatBot is primarily through the chat method, where users provide a prompt, and the bot displays the response after processing. Internally, the converse method updates the conversation history and uses the conversation chain to generate a response. This method's utility lies in its ability to append each interaction to the history log, ensuring all discourse components are retained for future reference or undo actions.\n",
    "\n",
    "Memory management functions like print_memory, clear_memory, and undo provide users and developers with tools to view, reset, or revert the conversation state, thus offering flexibility in managing the dialogue flow and content. Additional functionalities to save and load conversation history are provided through save_history and load_history, utilizing Python’s pickle module for object serialization.\n",
    "\n",
    "This class structure not only facilitates robust conversation handling and memory management but also showcases the integration of advanced language models in practical applications, demonstrating the potential of AI in enhancing interactive software solutions. Through such a detailed setup, ChatBot serves as a comprehensive framework for building interactive, memory-aware chatbot systems."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3.11 (genai)",
   "language": "python",
   "name": "genai"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
